import React, { useRef, useEffect, useState, useImperativeHandle } from "react";
import { Select, Space, Input, message, Spin } from 'antd';
import { CmdbContent, CmdbHeader, useModelAssociateType, NameSpaceBtn} from "@/components";
import cmdbres from "@/data/cmdbres";
import request from "@/utils/request";
import "./index.less"
import G6 from '@antv/g6';
import registerEdge from './config/register-edge';
import registerNode from './config/register-node';
import { G6ToolBar, G6Menu, G6Legend } from './config/register-plugins';
import { defaultNodeConfig, defaultEdgeConfig, defaultLayout } from "./config/default";
import { initData, getLayout } from "./config/utils";
import HelpTipModal from './components/helpTipModal';
import CreateModel from './components/createMainLine';
import DeleteMainLine from './components/deleteMainLine';
import DetailsModal from '../components/detailsModal';
import CreateRelation from '../components/createRelation';
import EditRelation from '../components/editRelation';
import DeleteRelation from '../components/deleteRelation';
const GRAPH_ID = "model-graph-container";

const modelTopology = ({ history, match, location, cRef, isEdit, hideModels }) => {
    const domRef = useRef(null);
    const graphRef = useRef(null)
    let graph = graphRef.current;
    const [showHelp, setShowHelp] = useState(false);
    const [detailInfo, setDetailInfo] = useState({});
    const [showDetailModal, setShowDetailModal] = useState(false);
    const [showAddNodeModal, setShowAddNodeModal] = useState(false);
    const [showCreateRelation, setShowCreateRelation] = useState(false);
    const [showEditRelation, setShowEditRelation] = useState(false);
    const [showDeleteRelation, setShowDeleteRelation] = useState(false);
    const [showDeleteMainLine, setShowDeleteMainLine] = useState(false);
    const [{associateType}, loading] = useModelAssociateType(); // 翻译关联关系
    const [topoData, setTopoData] = useState();
    const [curEdge, setCurEdge ] = useState(null);
    const [targetData, setTargetData] = useState([]);// 目标模型数据
    const [newEdge, setNewEdge] = useState();// 新增的边
    const [graphLoading, setGraphLoading] = useState(false);

    useEffect(() => {
      fetchData();
    }, [hideModels]);

    const fetchData = async() => {
      setGraphLoading(true);
      const [nodes, edges1, edges2] = await Promise.all([queryModel(), queryMainLine(), queryAllModelAssociate()]);
      if(nodes && edges1 && edges2) {
        setTopoData({nodes, edges: edges1.concat(edges2)});
      }
      setGraphLoading(false);
    };

    const queryModel = async () => {
        try {
            let res = await request({
                ...cmdbres.queryModelList,
                params: {
                    namespace: 'default'
                },
            });
            if(res && res.code == 200) {
              const nodes = [];
              const treeDataIteration = (data, topFloor, level) => {
                data.map(item => {
                  if(level == 1) {
                    topFloor = item;
                  }
                  if(item.cmModuleId) {
                    item.topFloorId = topFloor?.id;
                    item.topFloorName = topFloor?.moduleClassificationName;
                    item.topFloorCode = topFloor?.moduleClassificationCode;
                    item.topFloorIndex = topFloor?.id;
                    if(!hideModels?.includes(item.cmModuleId)) {// 去除隐藏的模型
                      nodes.push(item);
                    }
                  }

                  item.children = item.children || [];
                  if(item.definitions) item.children = item.children .concat(item.definitions);
                  if(item.children.length) treeDataIteration(item.children, topFloor, -1);
                });
              };
              treeDataIteration(res.data, null, 1);
              return nodes;
            } else {
              return [];
            }
        } catch (error) {
          return [];
        }
    };

    const queryAllModelAssociate = async (params = { current: 1, pageSize: 10 }) => {
      try {
          const res = await request({
              ...cmdbres.queryAllModelAssociate,
              data: {
                pageSize: 99999999,
                pageNumber: 1,
            },
          });
          return res && res.data ? res.data : [];
      } catch (error) {
          return [];
      } 
    };
    const innerMainLine = ['biz:set', 'set:service'];
    //查询拓扑组成的模型关系
    const queryMainLine = async () => {
        try {
            const res = await request({
                ...cmdbres.queryMainLine,
                params: {},
            });
            let arr = [];
            if(res && res.data) {
              res.data.map(item=> {
                if(item.nextModuleId) {
                  
                  arr.push({
                    srcModuleId: item.moduleId,
                    srcModuleCode: item.moduleCode,
                    srcModuleName: item.moduleName,
                    destModuleId: item.nextModuleId,
                    destModuleCode: item.nextModuleCode,
                    destModuleName: item.nextModuleName,
                    associateType: 'cm_mainline',
                    woIsSystem: innerMainLine.includes(`${item.moduleId}:${item.nextModuleId}`)
                  })
                }
              })
            }
            return arr
        } catch (error) {
            console.log(error);
        } 
    };

    useEffect(() => {
      if(!(associateType && topoData)) return;
      const {data, moduleMap} = initData(topoData, associateType);
      graph = createGraphic(moduleMap);
      graph.read(data);
      // graph.refresh();
      // 关闭局部渲染解决缩放或者拖拽引起的残影问题（关闭会影响性能，临时解决办法）
      graph.get('canvas').set('localRefresh', false);
      bindEvents();

      return () => {
        if(graph) {
          graph.destroy();
        }
      };
    },[associateType, topoData])

    const createGraphic = (moduleMap) => {
        // 注册自定义节点
        registerEdge(G6, isEdit);
        // 注册自定义边
        registerNode(G6);
  
        let modes = [
          'drag-canvas',
          'drag-node',
          'zoom-canvas',
        ]
        if(isEdit) modes.push('create-edge');
        const container = document.getElementById(GRAPH_ID);
        const tree = new G6.Graph({
          container: domRef.current,
          width: container.offsetWidth,
          height: container.offsetHeight,
          defaultNode: defaultNodeConfig,
          defaultEdge: defaultEdgeConfig,
          layout: {
            pipes: getLayout(moduleMap, container)
          },
          animate: true,
          modes: {
            default: modes,
          },
          plugins: [
            new G6.Grid(),
            new G6.Minimap({
              size: [200, 150],
            }),
            G6Menu(G6, menuHandles, isEdit),
            G6ToolBar(G6, setShowHelp),
          ],
        });

        graphRef.current = tree;
        return tree;
    };

    const bindEvents = () => { 
      graph.on('node:mouseenter', (evt) => {
        const node = evt.item;
        const edges = node.getEdges();
        graph.setItemState(node, 'active', true);
        edges.forEach((edge) => graph.setItemState(edge, 'running', true));
      });
      graph.on('node:mouseleave', (evt) => {
        const node = evt.item;
        const edges = node.getEdges();
        graph.setItemState(node, 'active', false);
        edges.forEach((edge) => graph.setItemState(edge, 'running', false));
      });
      graph.on('edge:mouseenter', (evt) => {
        const edge = evt.item;
        graph.setItemState(edge, 'hover', true);
      });

      graph.on('edge:mouseleave', (evt) => {
          const edge = evt.item;
          graph.setItemState(edge, 'hover', false);
      }); 
      graph.on('canvas:click', (evt) => {
        graph.getNodes().forEach((node) => {
          graph.clearItemStates(node);
        });
      });
      graph.on('edge:click', (evt)=> {
        if(!isEdit) return;
        const {item, target} = evt;
        if(target.cfg.name == 'add-node-shape') {
          setCurEdge(evt);
          setShowAddNodeModal(true);
        }
      });
      graph.on('aftercreateedge', ({edge})=> {
        const source = edge?.getSource()?.getModel();
        const target = edge?.getTarget()?.getModel();
        if(source && target && source.id == target.id) {
          edge.hide();
          return;
        }
        let flag = true;
        const edges = graph.getEdges();
        edges.map((item, index) => {
          if(index == edges.length - 1) return;
          if(!item.isVisible()) return;
          const _source = item.getSource().getModel();
          const _target = item.getTarget().getModel();
          if((_source.id == source.id && _target.id == target.id) ||(_source.id == target.id && _target.id == source.id)) {
            edge.hide();
            flag = false;
          }
        })
        if(flag) {
          setDetailInfo(source);
          setTargetData([target]);
          setNewEdge(edge);
          setShowCreateRelation(true);
        }
      })
    }
    const menuHandles = {
      queryDetail(item) {
        const model = item.getModel();
        setDetailInfo(model);
        setShowDetailModal(true);
      },
      editRelation(item) {
        const model = item.getModel();
        if(item.destroyed  || model.associateType == "cm_mainline") return true;
        if(model) {
          setCurEdge(model);
          setShowEditRelation(true);
        }
      },
      deleteRelation(item) {
        const model = item.getModel();
        if(item.destroyed) return true;
        if(model) {
          setCurEdge(model);
          setShowDeleteRelation(true);
        }
      },
      deleteMainLine(item) {
        const model = item.getModel();
        if(item.destroyed) return true;
        if(model) {
          setCurEdge(model);
          setShowDeleteMainLine(true);
        }
      }
    };

    useImperativeHandle(cRef, () => ({
      onRefresh: async () => {
          fetchData();
      },
  }));

    return (
      <CmdbContent>
        <Spin spinning={graphLoading} tip="Loading...">
          <div style={{ width: '100%', height: 710, position: 'relative' }}>
              <div ref={domRef} id={GRAPH_ID} style={{height: '100%'}} ></div>
          </div>
        </Spin>
        <HelpTipModal visible={showHelp} setVisible={setShowHelp}/>
        <DetailsModal visible={showDetailModal} setVisible={setShowDetailModal} info={detailInfo}/>
        <CreateModel 
          visible={showAddNodeModal} 
          setVisible={setShowAddNodeModal} 
          onCreateFinish={fetchData} 
          edge={curEdge}
        />
        {showCreateRelation&&<CreateRelation
            onCreateFinish={(flag)=>{
              if(flag) {
                fetchData();
              } else {
                if(newEdge) {
                  graph.removeItem(newEdge);
                  setNewEdge();
                }
              }
            }}
            visible={showCreateRelation}
            setVisible={setShowCreateRelation}
            info={detailInfo}
            targetData={targetData}
        />}
        {showEditRelation&&<EditRelation
            onCreateFinish={()=>{fetchData()}}
            visible={showEditRelation}
            setVisible={setShowEditRelation}
            info={curEdge}
        />}
        <DeleteRelation
            onDeleteFinish={()=>{fetchData()}}
            visible={showDeleteRelation}
            setVisible={setShowDeleteRelation}
            info={curEdge}
        />
        <DeleteMainLine
            onDeleteFinish={()=>{fetchData()}}
            visible={showDeleteMainLine}
            setVisible={setShowDeleteMainLine}
            info={curEdge}
            history={history}
        />
      </CmdbContent>
    )
}

export default modelTopology;
  

